// Copyright (c) 2002-2003, Sony Computer Entertainment America
// Copyright (c) 2002-2003, Craig Reynolds <craig_reynolds@playstation.sony.com>
// Copyright (C) 2007 Bjoern Graf <bjoern.graf@gmx.net>
// Copyright (C) 2007 Michael Coles <michael@digini.com>
// All rights reserved.
//
// This software is licensed as described in the file license.txt, which
// you should have received as part of this distribution. The terms
// are also available at http://www.codeplex.com/SharpSteer/Project/License.aspx.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;
using Etapa1.Pedestrian;


namespace Bnoerj.AI.Steering.Boids
{
	using ProximityDatabase = IProximityDatabase<IVehicle>;
	using ProximityToken = ITokenForProximityDatabase<IVehicle>;
    using PloobsEngine;
    using PloobsEngine.SceneControl;
    using PloobsEngine.Modelo;    
    using PloobsEngine.Physics.Bepu;
    using PloobsEngine.Material;
    

	public class BoidsPlugIn : PlugIn
	{

        IWorld world;        
        EngineStuff engine;
        private bool keyActivated = true;
        private float keySensibility = 5;

        public float KeySensibility
        {
            get { return keySensibility; }
            set { keySensibility = value; }
        }

        public bool KeyActivated
        {
            get { return keyActivated; }
            set { keyActivated = value; }
        }

        public BoidsPlugIn(IWorld world,EngineStuff engine)
			: base()
		{
				flock = new List<Boid>();
            this.world = world;
            this.engine = engine;
		}


		public override String Name { get { return "Boids"; } }

		public override float SelectionOrderSortKey
		{
			get { return 0.03f; }
		}

		public override void Open()
		{
			// make the database used to accelerate proximity queries
			cyclePD = -1;
			NextPD();

			// make default-sized flock
			population = 0;
			for (int i = 0; i < 200; i++) AddBoidToFlock();			
		}        

		public override void Update(float currentTime, float elapsedTime)
		{
            if (keyActivated)
            {
                if (Keyboard.GetState().IsKeyDown(Keys.I))
                {
                    for (int i = 0; i < 200; i++)
                    {
                        flock[i].WorldCenter += Vector3.Up * keySensibility;
                    }
                }
                if (Keyboard.GetState().IsKeyDown(Keys.H))
                {
                    for (int i = 0; i < 200; i++)
                    {
                        flock[i].WorldCenter += Vector3.Down * keySensibility;
                    }
                }
                if (Keyboard.GetState().IsKeyDown(Keys.L))
                {
                    for (int i = 0; i < 200; i++)
                    {
                        flock[i].WorldCenter += Vector3.Right * keySensibility;
                    }
                }
                if (Keyboard.GetState().IsKeyDown(Keys.J))
                {
                    for (int i = 0; i < 200; i++)
                    {
                        flock[i].WorldCenter += Vector3.Left * keySensibility;
                    }
                }
                if (Keyboard.GetState().IsKeyDown(Keys.K))
                {
                    for (int i = 0; i < 200; i++)
                    {
                        flock[i].WorldCenter += Vector3.Backward * keySensibility;
                    }
                }
                if (Keyboard.GetState().IsKeyDown(Keys.I))
                {
                    for (int i = 0; i < 200; i++)
                    {
                        flock[i].WorldCenter += Vector3.Forward * keySensibility;
                    }
                }
            }

			// update flock simulation for each boid
			for (int i = 0; i < flock.Count; i++)
			{
				flock[i].Update(currentTime, elapsedTime);
			}
		}

		public override void Redraw(float currentTime, float elapsedTime)
		{			
		}

		public override void Close()
		{
			// delete each member of the flock
			while (population > 0) RemoveBoidFromFlock();

			// delete the proximity database
			pd = null;
		}

		public override void Reset()
		{
			// reset each boid in flock
			for (int i = 0; i < flock.Count; i++) flock[i].Reset();		
		}

		// for purposes of demonstration, allow cycling through various
		// types of proximity databases.  this routine is called when the
		// Demo user pushes a function key.
		public void NextPD()
		{
			// save pointer to old PD
			ProximityDatabase oldPD = pd;

			// allocate new PD
			const int totalPD = 2;
			switch (cyclePD = (cyclePD + 1) % totalPD)
			{
			case 0:
				{
					Vector3 center = Vector3.Zero;
					const float div = 10.0f;
					Vector3 divisions = new Vector3(div, div, div);
					float diameter = Boid.worldRadius * 1.1f * 2;
					Vector3 dimensions = new Vector3(diameter, diameter, diameter);
					pd = new LocalityQueryProximityDatabase<IVehicle>(center, dimensions, divisions);
					break;
				}
			case 1:
				{
					pd = new BruteForceProximityDatabase<IVehicle>();
					break;
				}
			}

			// switch each boid to new PD
			for (int i = 0; i < flock.Count; i++) flock[i].NewPD(pd);

			// delete old PD (if any)
			oldPD = null;
		}

		public override void HandleFunctionKeys(Keys key)
		{
			switch (key)
			{
			case Keys.F1: AddBoidToFlock(); break;
			case Keys.F2: RemoveBoidFromFlock(); break;
			case Keys.F3: NextPD(); break;
			case Keys.F4: Boid.NextBoundaryCondition(); break;
			}
		}

		public override void PrintMiniHelpForFunctionKeys()
		{
#if IGNORED
        std.ostringstream message;
        message << "Function keys handled by ";
        message << '"' << name() << '"' << ':' << std.ends;
        Demo.printMessage (message);
        Demo.printMessage ("  F1     add a boid to the flock.");
        Demo.printMessage ("  F2     remove a boid from the flock.");
        Demo.printMessage ("  F3     use next proximity database.");
        Demo.printMessage ("  F4     next flock boundary condition.");
        Demo.printMessage ("");
#endif
		}

		public void AddBoidToFlock()
		{
            population++;
            Boid boid = new Boid(pd);
            flock.Add(boid);            

            SimpleModel sm = new SimpleModel("..\\Content\\Model\\block", "..\\Content\\Textures\\caixaTex");
            sm.LoadModelo();
            BoxObject pi = new BoxObject(new Vector3(0, 50, 100), 1, new Vector3(0.5f));
            ObjectMover om = new ObjectMover(pi);
            IShader shader = new NormalDeferred();
            shader.Initialize();
            IMaterial mat = new Material(shader, MaterialType.DEFERRED);
            SteerObject agent = new SteerObject(boid, mat, pi, sm);
            world.AddObject(agent);
            pi.Position = boid.Position;

		}

		public void RemoveBoidFromFlock()
		{
			if (population > 0)
			{
				// save a pointer to the last boid, then remove it from the flock
				population--;
				Boid boid = flock[population];
				flock.RemoveAt(population);

				// delete the Boid
				boid = null;
			}
		}

		// return an AVGroup containing each boid of the flock
		public override List<IVehicle> Vehicles
		{
			get { return flock.ConvertAll<IVehicle>(delegate(Boid v) { return (IVehicle)v; }); }
		}

		// flock: a group (STL vector) of pointers to all boids
		public List<Boid> flock;

		// pointer to database used to accelerate proximity queries
		public ProximityDatabase pd;

		// keep track of current flock size
		public int population;

		// which of the various proximity databases is currently in use
		public int cyclePD;
	}
}
